﻿using System;
using System.Threading;
using System.Windows.Threading;
using MadMediaManager.WPFSupport.Interfaces.Services.Threading;

namespace MadMediaManager.WPFSupport.Services.Threading
{
    /// <summary>
    /// This dispatcher is used at runtime by both Windows Forms and WPF. The WPF Dispatcher 
    /// class works within Windows Forms, so this appears to be safe.
    /// </summary>
    public class DispatcherWrapper : IDispatcher
    {
        private readonly Dispatcher _dispatcher;
        private readonly IDispatcherHooks _hooks;

        /// <summary>
        /// Initializes a new instance of the <see cref="DispatcherWrapper"/> class.
        /// </summary>
        public DispatcherWrapper()
            : this(Dispatcher.CurrentDispatcher) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="DispatcherWrapper"/> class.
        /// </summary>
        /// <param name="dispatcher">The dispatcher.</param>
        public DispatcherWrapper(Dispatcher dispatcher)
        {
            _dispatcher = dispatcher;
            _hooks = new DispatcherHooksWrapper(dispatcher.Hooks);
        }

        public Thread Thread
        {
            get { return _dispatcher.Thread; }
        }

        public bool HasShutdownStarted
        {
            get { return _dispatcher.HasShutdownStarted; }
        }

        public bool HasShutdownFinished
        {
            get { return _dispatcher.HasShutdownFinished; }
        }

        
        public IDispatcherHooks Hooks
        {
            get { return _hooks; }
        }

        public bool CheckAccess()
        {
            return _dispatcher.CheckAccess();
        }

        public void VerifyAccess()
        {
            _dispatcher.VerifyAccess();
        }

        public void BeginInvokeShutdown(DispatcherPriority priority)
        {
            _dispatcher.BeginInvokeShutdown(priority);
        }

        public void InvokeShutdown()
        {
            _dispatcher.InvokeShutdown();
        }

        public IDispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method)
        {
            return new DispatcherOperationWrapper(_dispatcher.BeginInvoke(priority, method));
        }

        public IDispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg)
        {
            return new DispatcherOperationWrapper(_dispatcher.BeginInvoke(priority, method, arg));
        }

        public IDispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg, params object[] args)
        {
            return new DispatcherOperationWrapper(_dispatcher.BeginInvoke(priority, method, args, args));
        }

        public IDispatcherOperation BeginInvoke(Delegate method, params object[] args)
        {
            return new DispatcherOperationWrapper(_dispatcher.BeginInvoke(method, args));
        }

        public IDispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args)
        {
            return new DispatcherOperationWrapper(_dispatcher.BeginInvoke(method, priority, args));
        }

        public object Invoke(DispatcherPriority priority, Delegate method)
        {
            return _dispatcher.Invoke(priority, method);
        }

        public object Invoke(DispatcherPriority priority, Delegate method, object arg)
        {
            return _dispatcher.Invoke(priority, method, arg);
        }

        public object Invoke(DispatcherPriority priority, Delegate method, object arg, params object[] args)
        {
            return _dispatcher.Invoke(priority, method, arg, args);
        }

        public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method)
        {
            return _dispatcher.Invoke(priority, timeout, method);
        }

        public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg)
        {
            return _dispatcher.Invoke(priority, timeout, method, arg);
        }

        public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg, params object[] args)
        {
            return _dispatcher.Invoke(priority, timeout, method, arg, args);
        }

        public object Invoke(Delegate method, params object[] args)
        {
            return _dispatcher.Invoke(method, args);
        }

        public object Invoke(Delegate method, DispatcherPriority priority, params object[] args)
        {
            return _dispatcher.Invoke(method, priority, args);
        }

        public object Invoke(Delegate method, TimeSpan timeout, params object[] args)
        {
            return _dispatcher.Invoke(method, timeout, args);
        }

        public object Invoke(Delegate method, TimeSpan timeout, DispatcherPriority priority, params object[] args)
        {
            return _dispatcher.Invoke(method, timeout, priority, args);
        }

        public DispatcherProcessingDisabled DisableProcessing()
        {
            return _dispatcher.DisableProcessing();
        }

        public event EventHandler ShutdownStarted
        {
            add { _dispatcher.ShutdownStarted += value; }
            remove { _dispatcher.ShutdownStarted -= value; }
        }

        public event EventHandler ShutdownFinished
        {
            add { _dispatcher.ShutdownFinished += value; }
            remove { _dispatcher.ShutdownFinished -= value; }
        }

        public event DispatcherUnhandledExceptionFilterEventHandler UnhandledExceptionFilter
        {
            add { _dispatcher.UnhandledExceptionFilter += value; }
            remove { _dispatcher.UnhandledExceptionFilter -= value; }
        }

        public event DispatcherUnhandledExceptionEventHandler UnhandledException
        {
            add { _dispatcher.UnhandledException += value; }
            remove { _dispatcher.UnhandledException -= value; }
        }

    }
}
